【第1224期】追根溯源:箭头函数的前世今生
前言
又快到月末了,周末就看看“故事”吧,今日早读文章由@肖蜀黍投稿分享。
@肖蜀黍,曾服务于众安、腾讯,现为自由职业的全栈工程师,长期维护《趣你的大前端》知乎专栏。
正文从这开始~
Arrow Function(箭头函数),es6的新特性之一,你可能已经熟练使用并且爱上了它。但这个看似普通的语法糖,有着一个漫长而精彩的故事,本文将带你回到一百多年前,看看它是怎么走进我们世界的。
史前:第三次数学危机
在很久很久以前,人们很傻很天真,相信一切数字都可以表达为整数之比。直到公元前400年,毕达哥拉斯发现了无理数,引发第一次数学危机。
17世纪的晚期,无穷小的问题带来了第二次数学危机,幸运的是出来两位伟人:牛顿和莱布尼兹,用微积分的方式匡扶了即将倒下的数学大厦。
风平浪静不过两百年,又出来一个搞事情的家伙,叫做罗素(Bertrand Russell)。他提出一个问题,瞬间让数学家们炸锅了,史称第三次数学危机。
这个问题叫做理发师悖论,通俗的描述是这样的:
理发师的规矩是:只为不给自己理发的人理发。那么问题就来了,他应不应该给自己理发?
如果不应该,那他就属于不给自己理发的人,但按照规矩,他有应该给自己理发。
如果应该,那他就属于给自己理发的人,但按照规矩,他就不能给自己理发。
此悖论也可以用数学公式来描述:
如果有一个集合,它包含任何非己的元素,那么这个集合是否属于它本身呢?
惶恐:可计算性问题
危机产生后,人类再次陷入了深深的沉思:还有哪些问题是无法证明的?计算或者推理的边界在哪?怎么判定一个问题是否可解?如果无解,那原因又是什么?
要解除这个危机,首先必须定义可计算这一概念。20世纪30年代,搞数学的各路英雄好汉,纷纷加入了可计算性问题的研究。
丘奇通过建模的方式,很快找到一个神器,并命名曰:λ演算(lambda calculus)。λ演算是一种表达式,它由引入变量、参数、函数声明、函数应用组成。
与此同时,图灵(丘奇的学生,也是人工智能的爸爸)发明了图灵机。图灵机是一台假想的机器,能模拟人们用纸笔进行数学运算的过程。至此,邱奇-图灵论题已经成功的解决了在可计算理论中的判定性问题。
有了图灵机的灵感,冯·诺伊曼提出一个体系,抽象出输入设备、控制器、运算器、存储器、输出器等概念。并在此理论上,美国人制造了第一台计算机—埃尼阿克(ENIAC:Electronic Numerical Integrator And Computer)
神器:λ演算
究竟 λ演算
是什么鬼,竟然能间接引发人类的科技革命?因为λ演算研究的是函数的本质性问题,所以形式极其简单:
上面的E称为λ-表达式(expressions)或λ-terms,它的值有三种形式:
变量(variables)。
函数声明或抽象(function creation/abstraction)。需要注意是的,函数中有且仅有一个参数。在λx. E中,x是参数,E是函数体。
函数应用(function application)。也就是我们理解的函数调用,但官方术语就叫函数应用。
等一等, λ演算
中函数只有一个参数?那两个或者以上参数的函数,岂不是没法玩了?这样的λ演算,也未免太弱了吧?
非也,这正是λ的神奇之处!如果你想有多个参数,很简单,使用currying技术即可:
λx y.(+ x y)---->λx.(λ y.+ x y)
玩法是这样的:你调用了一个函数,这个函数返回另一个函数,返回的函数中存储保留了调用函数的变量。
似曾相识对不对,没错,currying就是闭包的鼻祖。
或者你也可以用Python的来实现:
def add(x):
returnlambda y: x+y
add(4)(3)//return 7
此外,还有更多玩法,比如用 λ演算
来定义变量、数值、键值对……
//定义Boolean类型
true=λx.λy. x
false=λx.λy. y
if E1 then E2 else E3 = E1 E2 E3
开拓:Lisp语言
公元1958年,受邱奇的λ演算的影响,出现了LISP编程语言。它有独特和完全括号的前缀符号表示法。它是现今第二悠久而仍广泛使用的高级编程语言。只有FORTRAN编程语言比它更早一年。
LISP 编程语族已经演变出许多种方言。现代最著名的通用编程语种是 Common LISP 和 Scheme。
再后来故事,我们就熟悉了,1994年JavaScript诞生了,它是一个超级大杂烩,看看它的这些干爹:
借鉴C语言的基本语法;
借鉴Java语言的数据类型和内存管理;
借鉴Scheme语言,将函数提升到”第一等公民”的地位;
借鉴Self语言,使用基于原型(prototype)的继承机制。
未来:函数式编程
最后,千呼万唤,屎都出来了。2015年,终于迎来了我们的主角:箭头函数。
(param1, param2,…, paramN)=>{ statements }
(param1, param2,…, paramN)=> expression
// 等同于: => { return expression; }
// 如果只有一个参数,圆括号是可选的:
(singleParam)=>{ statements }
singleParam =>{ statements }
// 无参数的函数需要使用圆括号:
()=>{ statements }
此外,由于Node的迅猛发展,以及React/Vue/Angular这些洪水猛兽,前端们喊出里一个新的口号:函数式编程。
这又是一个巨大的话题,会不会再次掀起腥风血雨?
最后,为你推荐
关于本文
作者:@肖蜀黍
原文:https://mp.weixin.qq.com/s/52wN6rPvbN5K_Cp0OkEHBQ